package io.github.shenbinglife.jlock;

import io.github.shenbinglife.jlock.exception.LockFailedException;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.Objects;

/**
 * 基于文件的独占锁，不可重入
 *
 * @author shenbing
 * @date 2022/4/21
 */
public class JClientAwareFileLock extends JFileLock {


  public JClientAwareFileLock(File file) {
    super(file);
  }

  public JClientAwareFileLock(String file) {
    super(file);
  }

  public JClientAwareFileLock(Path path) {
    super(path);
  }

  @Override
  public void unlock() {
    String cur = LockUtils.currentClientId();
    String lockedClient = fileClientId();
    if (!Objects.equals(cur, lockedClient)) {
      throw new LockFailedException("Can not unlock the file not belongs to cur client: " + cur);
    }
    super.unlock();
  }

  @Override
  protected boolean tryLockOnce() {
    boolean success = super.tryLockOnce();
    if (success) {
      try {
        writeClientIdToFile();
      } catch (IOException e) {
        file.delete();
        throw new LockFailedException("Can not write client id to file", e);
      }
    }
    return success;
  }


  public String fileClientId() {
    try (BufferedReader reader = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8)) {
      return reader.readLine();
    } catch (IOException e) {
      throw new LockFailedException("Can not read client id from file", e);
    }
  }

  public String writeClientIdToFile() throws IOException {
    String clientId = LockUtils.currentClientId();
    try (BufferedWriter writer = Files.newBufferedWriter(file.toPath(), StandardCharsets.UTF_8,
        StandardOpenOption.CREATE)) {
      writer.append(clientId);
    }
    return clientId;
  }

  public static void main(String[] args) {
    JClientAwareFileLock jClientAwareFileLock = new JClientAwareFileLock("b.lock");
    jClientAwareFileLock.unlock();
  }
}
